package com.yifeng.repo.base.utils.common;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.util.concurrent.RateLimiter;
import lombok.extern.slf4j.Slf4j;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

import static com.yifeng.repo.base.constant.BaseConstant.ONE_SECOND;
import static com.yifeng.repo.base.constant.BaseConstant.ONE_SECOND_MS;


/**
 * Created by daibing on 2021/8/25.
 * @deprecated ：建议使用 com.yifeng.repo.base.utils.common.RateLimiterManager
 */
@Slf4j
@SuppressWarnings("UnstableApiUsage")
public class FireLimiter {
    private static final Cache<String, RateLimiter> CACHE = CacheBuilder.newBuilder()
            .initialCapacity(32)
            .expireAfterAccess(1, TimeUnit.MINUTES)
            .build();
    /**
     * qps
     */
    private final double limit;
    private final Long periodSecond;

    /**
     * 默认1秒周期内的令牌数量
     */
    public FireLimiter(double limit) {
        this.limit = limit;
        this.periodSecond = ONE_SECOND;
    }

    /**
     * 指定周期内的令牌数量
     */
    public FireLimiter(double limit, long periodSecond) {
        this.limit = limit / periodSecond;
        this.periodSecond = periodSecond;
    }

    public boolean isLimit(String accessKey) {
        try {
            RateLimiter limiter = CACHE.get(accessKey, new Callable<RateLimiter>() {
                @Override
                public RateLimiter call() throws Exception {
                    return RateLimiter.create(limit);
                }
            });
            // 可以在timeout过期之前获取到许可就返回true，否则立即返回false（无需等待）
            if (!limiter.tryAcquire(periodSecond, TimeUnit.SECONDS)) {
                log.warn("access_key: {} limited", accessKey);
                return true;
            }
        } catch (ExecutionException e) {
            log.warn("create limit fail: accessKey={}, error=", accessKey, e);
        }
        return false;
    }

    public static void main(String[] args) throws InterruptedException {
        System.out.println("fire limiter start to do...");
        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS");
        FireLimiter limiter1 = new FireLimiter(10);
        for (int i = 0; i < 100; i++) {
            System.out.printf("%3d %s limit: %s%n", i, sdf.format(new Date()), limiter1.isLimit("limiter1"));
//            if (i % 15 == 3) {
//                System.out.print("sleep start...");
//                Thread.sleep(300);
//                System.out.println("sleep end...");
//            }
        }
        System.out.println("first test finished!\n");

        FireLimiter limiter2 = new FireLimiter(30, 60);
        for (int i = 0; i < 100; i++) {
            System.out.printf("%3d %s limit: %s%n", i, sdf.format(new Date()), limiter2.isLimit("limiter2"));
            if (i % 5 == 3) {
                System.out.print("sleep start...");
                Thread.sleep(2 * ONE_SECOND_MS);
                System.out.println("sleep end...");
            }
        }
    }
}
